﻿using LiteNetLib;
using LiteNetLib.Utils;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;

namespace BToolkit
{
    //使用MonoBehaviour仅是为了在Unity停止时能自动结束子线程
    public class NetServer : MonoBehaviour, INetEventListener
    {
        public event Action<ProtoBase> onReceiveOnSubThread;
        public bool isListening { get { return server != null && server.IsRunning; } }

        private NetServer() { }
        private NetManager server;
        private NetDataWriter writer;
        private string connectKey;
        private int maxConnectLimit;
        private bool isRun;

        public static NetServer Create(int maxConnectLimit = 10, string tag = null)
        {
            GameObject go = new GameObject(tag != null ? $"NetServer_{tag}" : "NetServer");
            DontDestroyOnLoad(go);
            NetServer server = go.AddComponent<NetServer>();
            server.maxConnectLimit = maxConnectLimit;
            return server;
        }

        public bool StartListen(int port, string key)
        {
            if (server == null)
            {
                this.connectKey = key;
                server = new NetManager(this);
                server.BroadcastReceiveEnabled = false;
                server.NatPunchEnabled = true;
                server.UpdateTime = 15;
                writer = new NetDataWriter();
                Task.Run(async () =>
                {
                    isRun = true;
                    while (isRun)
                    {
                        server.PollEvents();
                        await Task.Delay(15);
                    }
                });
                return server.Start(port);
            }
            Debug.LogError("NetServer已经在运行，无需重复启动");
            return false;
        }

        public void OnConnectionRequest(ConnectionRequest request)
        {
            if (server.ConnectedPeersCount < maxConnectLimit)
            {
                request.AcceptIfKey(connectKey);
            }
            else
            {
                request.Reject();
            }
        }

        public void OnNetworkError(IPEndPoint endPoint, SocketError socketError)
        {
            Debug.LogError($"[NetServer] {socketError}");
            TextDebug.instance?.Log($"[NetServer] {socketError}");
        }

        public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
        {
        }

        public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod)
        {
            string msg = reader.GetString();
            //Debug.Log($"[NetServer] OnNetworkReceive 收到消息，开始准发: {msg}");
            ProtoBase proto = LitJson.JsonMapper.ToObject<ProtoBase>(msg);
            proto.fromPeerId = peer.Id;
            onReceiveOnSubThread?.Invoke(proto);
            msg = LitJson.JsonMapper.ToJson(proto);

            writer.Reset();
            writer.Put(msg);
            if (proto.targetType == -1)
            {
                //排除自己
                foreach (var p in server.ConnectedPeerList)
                {
                    if (p != peer)
                    {
                        p.Send(writer, DeliveryMethod.ReliableOrdered);
                    }
                }
            }
            else if (proto.targetType == 0)
            {
                //全网发送
                server.SendToAll(writer, DeliveryMethod.ReliableOrdered);
            }
            else
            {
                //指定一个对象
                foreach (var p in server.ConnectedPeerList)
                {
                    if (p.Id == proto.toPeerId)
                    {
                        p.Send(writer, DeliveryMethod.ReliableOrdered);
                        break;
                    }
                }
            }
            reader.Recycle();
        }

        public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
        {
        }

        public void OnPeerConnected(NetPeer peer)
        {
            Debug.Log($"[NetServer] 有客户端连接：peerId:{peer.Id}");
            string msg = LitJson.JsonMapper.ToJson(new ProtoBase() { id = ProtoID.NewConnection, fromPeerId = peer.Id });
            writer.Reset();
            writer.Put(msg);
            //有新人连接，全网通知
            foreach (var p in server.ConnectedPeerList)
            {
                p.Send(writer, DeliveryMethod.ReliableOrdered);
            }
        }

        public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
        {
            Debug.LogError($"[NetServer] 连接已断开:peerId:{peer.Id}");
            TextDebug.instance?.Log($"[NetServer] 连接已断开:peerId:{peer.Id}");
        }

        public void Stop()
        {
            isRun = false;
            onReceiveOnSubThread = null;
            server?.Stop();
            server = null;
        }

        private void OnDestroy()
        {
            Stop();
        }
    }
}